TypeScript 50.6%
JavaScript 46.1%
SQL 2.1%
Shell 0.6%
CSS 0.5%
1import { NextRequest, NextResponse } from "next/server";2import { z } from "zod";3import { assertSameOrigin, requireUser, clientIp } from "@/lib/auth/session";4import { openInquiry } from "@/lib/inquiries/service";5import { hit } from "@/lib/auth/ratelimit";6import { ipHash } from "@/lib/auth/crypto";7import { apiError, handle, parseBody } from "@/lib/api";8export const dynamic = "force-dynamic";9const Body = z.object({ body: z.string().trim().min(10).max(3000), category: z.enum(["INFO", "VISIT", "OFFER"]).default("INFO"), idempotencyKey: z.string().max(80).optional() });10export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {11 try { await assertSameOrigin(); const u = await requireUser(); const { id } = await params; const b = await parseBody(req, Body);12 const rl = await hit(`inq:${u.id}`, 20, 3600); const rl2 = await hit(`inq:ip:${ipHash(await clientIp())}`, 40, 3600); if (!rl.ok || !rl2.ok) return apiError(429, "rate_limited", "Trop de demandes envoyées. Réessayez plus tard.");13 const inq = await openInquiry(id, u.id, b.category, b.body, b.idempotencyKey); return NextResponse.json({ ok: true, inquiryId: inq.id }, { status: 201 }); } catch (e) { return handle(e); }14}15